package gate

import (
	"fmt"
	"github.com/golang/protobuf/proto"
	. "leaf/core/error"
	"leaf/core/log"
	. "leaf/core/msg"
	"leaf/core/time"
	"reflect"
)

var (
	Error_Processor_MessageType        = fmt.Errorf("msg type error")
	Error_Processor_MessageNil         = fmt.Errorf("msg is nil")
	Error_Processor_HandlerNotFind     = fmt.Errorf("handle not find")
	Error_Processor_MsgIdRequestRepeat = fmt.Errorf("msg id requset repeat")
)

var (
	OPT_REG_FIRSTMSG int32 = 1 << 0
	OPT_REG_REQLIMIT int32 = 1 << 1
)

type MsgProcessor struct {
	handlers      map[uint16]*MsgHandler
	innerHandlers map[uint16]*InnerMsgHandler
	firstId       uint16
	msgLimit      map[uint16]bool
}

func NewMsgProcessor() *MsgProcessor {
	p := new(MsgProcessor)
	p.handlers = make(map[uint16]*MsgHandler)
	p.msgLimit = map[uint16]bool{}
	return p
}

func (p *MsgProcessor) Register(requestMsg interface{}, replyMsg interface{}, handler func(agent Agent, msg *PMsg) *Error, opts ...int32) {
	requestType := reflect.TypeOf(requestMsg)
	if !CheckMessage(requestType) {
		log.Error("Register requestType:%v check message err", requestType)
		return
	}

	var replyType reflect.Type
	var replyId uint16
	if replyMsg != nil {
		replyType = reflect.TypeOf(replyMsg)
		replyId = GetMessageId(replyType)
		if replyId == 0 {
			log.Error("Register replyType:%v check message err", replyType)
			return
		}
	}

	requestId := GetMessageId(requestType)
	if _, ok := p.handlers[requestId]; ok {
		log.Error("Register handle of %v exist", requestId)
		return
	}

	msgHandler := new(MsgHandler)
	msgHandler.Func = handler
	msgHandler.RequestId = requestId
	msgHandler.RequestType = requestType
	msgHandler.ReplyId = replyId
	msgHandler.ReplyType = replyType

	if len(opts) > 0 {
		if opts[0]&OPT_REG_FIRSTMSG > 0 {
			if p.firstId == 0 {
				p.firstId = requestId
			} else {
				log.Error("register handler first repeat...,requestId:%v", requestId)
			}
		}

		if opts[0]&OPT_REG_REQLIMIT > 0 {
			p.msgLimit[requestId] = true
		}
	}
	p.handlers[requestId] = msgHandler
}

func (p *MsgProcessor) InnerRegister(msg proto.Message, handler func(agent Agent, msg proto.Message) *Error) {
	requestType := reflect.TypeOf(msg)
	if !CheckMessage(requestType) {
		log.Error("Register requestType:%v check message err", requestType)
		return
	}

	var requestId = GetMessageId(requestType)
	if _, ok := p.handlers[requestId]; ok {
		log.Error("Register handle of %v exist", requestId)
		return
	}

	msgHandler := new(InnerMsgHandler)
	msgHandler.Func = handler
	msgHandler.RequestId = requestId
	msgHandler.RequestType = requestType

	p.innerHandlers[requestId] = msgHandler
}

func (p *MsgProcessor) GetHandler(msgId uint16) *MsgHandler {
	if msgHandler, ok := p.handlers[msgId]; ok {
		return msgHandler
	}
	return nil
}

func (p *MsgProcessor) GetInnerHandler(msgId uint16) *InnerMsgHandler {
	if msgHandler, ok := p.innerHandlers[msgId]; ok {
		return msgHandler
	}
	return nil
}

func (p *MsgProcessor) ProccessMsg(agent Agent, head *MessageHead, bytes []byte) (*PMsg, error) {
	if head.Type != MessageType_Msg {
		return nil, Error_Processor_MessageType
	}

	msg := new(PMsg)
	msg.Request = NewMessageFromBytes(head, bytes)
	if msg.Request == nil || msg.Request.Msg == nil {
		return nil, Error_Processor_MessageNil
	}

	msgHandler := p.GetHandler(head.MsgId)
	if msgHandler == nil {
		return nil, Error_Processor_HandlerNotFind
	}

	var protoMsg proto.Message
	if msgHandler.ReplyType != nil {
		var ok bool
		var msgType = msgHandler.ReplyType
		if msgType.Kind() == reflect.Ptr {
			msgType = msgType.Elem()
		}
		protoMsg, ok = reflect.New(msgType).Interface().(proto.Message)
		if !ok {
			return nil, Error_Processor_MessageType
		}
	}
	msg.Reply = new(Message)
	msg.Reply.MessageHead = *head
	msg.Reply.Msg = protoMsg

	gateAgent := agent.(*GatAgent)
	if p.msgLimit[msg.Request.MsgId] {
		if _, ok := gateAgent.msgLimit[msg.Request.MsgId]; ok {
			return nil, Error_RequestMsgRepeat
		}
		gateAgent.msgLimit[msg.Request.MsgId] = time.TimeStamp
		defer delete(gateAgent.msgLimit, msg.Request.MsgId)
	}

	if p.firstId != 0 {
		if p.firstId != msg.Request.MsgId {
			if agent.UserData() == nil {
				msg.Reply.Code = Error_MsgError.Code()
				return msg, nil
			}
		} else {
			if agent.UserData() != nil {
				msg.Reply.Code = Error_UserDataError.Code()
				return msg, nil
			}
		}
	}

	agent.Lock()
	defer agent.ULock()
	if err := msgHandler.Func(agent, msg); err != nil {
		msg.Reply.Code = err.Code()
	}
	return msg, nil
}

func (p *MsgProcessor) ProccessInnerMsg(agent Agent, msg proto.Message) error {
	msgId := GetMessageId(reflect.TypeOf(msg))
	if msgId == 0 {
		return Error_Processor_MessageType
	}

	handler := p.GetInnerHandler(msgId)
	if handler == nil {
		return Error_Processor_HandlerNotFind
	}

	agent.Lock()
	defer agent.ULock()
	if err := handler.Func(agent, msg); err != nil {
		return err
	}
	return nil
}
